#include "TraceReflection.h"
#include "Camera.h"
#include <iostream>


Color TraceReflection::TraceRay( const Ray& ray, int depth) const
{
    ContactData data;
    //if we are a shadow ray, we dont need the closest contact!
    if(depth == 10)
        data = m_scene->CheckContact(ray, false);
    else
        data = m_scene->CheckContact(ray);
    // if this ray hit something
    //10 == shadow ray, so as an early out return the 10.5f code
    if(depth ==10 && data.m_hit )
    {
        Color c;
        c.m_a = 10.5f;
        return c;
    }
    //Else, we are either a reflection ray or a source
    if (data.m_hit && depth <= 3)   
    {
        Color RETURN_COLOR;
        //check if this is in shadow
        Ray shadow;
        shadow.m_origin = data.m_hitPoint;
        float shade = 1.0f;
        for( unsigned int i = 0; i < m_scene->GetLights().size(); ++i)
        {
            Vec3 lightDir;
            if(m_scene->GetLights()[i]->IsDirectional())
                lightDir = m_scene->GetLights()[i]->GetDirection();
            else
            {
                Vec3 toLight = shadow.m_origin - m_scene->GetLights()[i]->GetPosition();
                toLight= toLight.normalise();
            }
            shadow.m_dir = lightDir.GetInverted();
            shadow.m_hitObject = data.m_hitTarget;
            Color Shadow_Test = TraceRay(shadow, 10);
            if(Shadow_Test.m_a == 10.5f)
                shade -= 1.0f/(float)m_scene->GetLights().size();
        }


        //check if we can reflect something
        if(data.m_hitTarget->Reflect())
        {
            Ray reflection; 
            reflection.m_origin = data.m_hitPoint;
            reflection.m_dir = ray.m_dir.Reflect(data.m_hitNormal);
            reflection.m_dir.normalise();
            reflection.m_hitObject = data.m_hitTarget;
            Color Reflection_Color = TraceRay(reflection, depth+1);        
            // if we do not hit anything with the reflection ray, use the old contact data
            // for the original hit
            if(Reflection_Color.m_a == 1.5f)
            {
                return RayTracer::ShadeThis(data) * shade*data.m_hitTarget->GetReflectance();
            }
            else //our color has been calculated depending on what we hit with the reflection vector, so return the combo
            {
                RETURN_COLOR += Reflection_Color;
                return (RayTracer::ShadeThis(data) + 
                                            (RETURN_COLOR *data.m_hitTarget->GetReflectance())) * 0.5f * shade;
            }
        }
        else //if this is not reflective or transparent
        {
            return RayTracer::ShadeThis(data) * shade;
        }
    }
    else if(depth == 0)
    {
        return m_scene->m_clearColor;
    }
    else
    {
        Color c;
        c.m_a = 1.5f;
        return c;
    }
}
